package com.mh.common;

import com.mh.dao.AssetAccountDao;
import com.mh.dao.AssetChangeDao;
import com.mh.dto.vo.TransferVo;
import com.mh.enums.AssetChangeType;
import com.mh.enums.BillType;
import com.mh.pojo.AssetAccount;
import com.mh.pojo.AssetChange;
import com.mh.pojo.Bill;
import com.mh.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * Date:2025/2/11
 * author:zmh
 * description: MQ消息监听 & 处理器
 **/

@Component
@Slf4j
@RequiredArgsConstructor
@Transactional
public class RabbitMessageListener {

    // 处理用户添加账本
    private final UserService userService;

    // 资产账户操作
    private final AssetAccountDao assetAccountDao;

    // 资产变动表操作
    private final AssetChangeDao assetChangeDao;

    // 转账
    @RabbitListener(queues = "transfer")
    public void transfer(TransferVo transferVo) {
        log.info("MQ：转账，开始异步记录账户资金变动信息...");
        try {
            // 记录两个账户的资金变动
            // 记录转出
            AssetAccount assetAccountOfOut = assetAccountDao.selectById(transferVo.getFromId());
            if (assetAccountOfOut == null) {
                log.error("MQ转账失败：转出账户不存在，账户ID: {}", transferVo.getFromId());
                return;
            }
            // 构造资金变动数据对象
            AssetChange assetChange = new AssetChange(transferVo.getFromId(), transferVo.getAmount(), 
                    assetAccountOfOut.getBalance(), AssetChangeType.TRANSFER.getCode(), 0, 
                    "转账到账户：" + transferVo.getToId());
            assetChangeDao.insert(assetChange);

            // 记录转入
            AssetAccount assetAccountOfIn = assetAccountDao.selectById(transferVo.getToId());
            if (assetAccountOfIn == null) {
                log.error("MQ转账失败：转入账户不存在，账户ID: {}", transferVo.getToId());
                return;
            }
            // 构造资金变动数据对象
            AssetChange assetChange2 = new AssetChange(transferVo.getToId(), transferVo.getAmount(), 
                    assetAccountOfIn.getBalance(), AssetChangeType.TRANSFER.getCode(), 0, 
                    "从账户：" + transferVo.getFromId() + " 转入");
            assetChangeDao.insert(assetChange2);
            log.info("MQ转账成功：转出账户{}，转入账户{}，金额{}", 
                    transferVo.getFromId(), transferVo.getToId(), transferVo.getAmount());
        } catch (Exception e) {
            log.error("MQ转账处理异常：{}", e.getMessage(), e);
            throw e; // 重新抛出异常以触发事务回滚
        }
    }

    @RabbitListener(queues = "addBill")
    public void addBill(Bill bill) {
        log.info("MQ：账单添加，开始异步处理账单资金变动信息，账单ID: {}", bill.getId());
        try {
            if (bill == null || bill.getAccountId() == null || bill.getAmount() == null) {
                log.error("MQ账单处理失败：账单数据不完整");
                return;
            }

            // 查询账户信息
            AssetAccount assetAccount = assetAccountDao.selectById(bill.getAccountId());
            if (assetAccount == null) {
                log.error("MQ账单处理失败：账户不存在，账户ID: {}", bill.getAccountId());
                return;
            }

            // 判断是支出还是收入操作，使用枚举避免魔法数字
            BillType billType = BillType.fromCode(bill.getType());
            if (billType == null) {
                log.error("MQ账单处理失败：账单类型无效，类型: {}", bill.getType());
                return;
            }

            // 计算新的余额（使用参数化方式，避免SQL注入）
            Double newBalance;
            if (billType == BillType.INCOME) {
                newBalance = assetAccount.getBalance() + bill.getAmount();
            } else {
                newBalance = assetAccount.getBalance() - bill.getAmount();
            }

            // 更新账户余额
            assetAccount.setBalance(newBalance);
            int update = assetAccountDao.updateById(assetAccount);
            if (update <= 0) {
                log.error("MQ账单处理失败：账户{}金额变动失败", bill.getAccountId());
                return;
            }

            log.info("MQ账单处理成功：账户{}金额变动成功，新余额: {}", bill.getAccountId(), newBalance);

            // 构造资金变动数据对象并插入表中
            AssetChange assetChange = new AssetChange(bill.getAccountId(), bill.getAmount(), 
                    newBalance, AssetChangeType.BILL.getCode(), bill.getId(), bill.getRemark());
            int insert = assetChangeDao.insert(assetChange);
            if (insert <= 0) {
                log.error("MQ账单处理失败：账户{}资金变动记录插入失败", bill.getAccountId());
            } else {
                log.info("MQ账单处理成功：账户{}资金变动记录插入成功", bill.getAccountId());
            }
        } catch (Exception e) {
            log.error("MQ账单处理异常：{}", e.getMessage(), e);
            throw e; // 重新抛出异常以触发事务回滚
        }
    }

    // 给新用户添加默认账本
    @RabbitListener(queues = "addBookForNewUser")
    public void addDefaultBookForNewUser(String openId) {
        log.info("MQ：新用户注册，开始给新用户添加默认账本，openId: {}", openId);
        try {
            if (openId == null || openId.trim().isEmpty()) {
                log.error("MQ新用户处理失败：openId为空");
                return;
            }
            if (!userService.addDefaultBookForNewUser(openId)) {
                log.error("MQ新用户处理失败：用户{}默认账本添加失败", openId);
            } else {
                log.info("MQ新用户处理成功：用户{}默认账本添加成功", openId);
            }
        } catch (Exception e) {
            log.error("MQ新用户处理异常：openId={}, 错误: {}", openId, e.getMessage(), e);
            throw e; // 重新抛出异常以触发事务回滚
        }
    }
}
